package com.aaron.registry.zk;

import com.aaron.enums.RpcErrorMessageEnum;
import com.aaron.exception.RpcException;
import com.aaron.extension.ExtensionLoader;
import com.aaron.loadbalance.LoadBalance;
import com.aaron.registry.ServiceDiscovery;
import com.aaron.registry.zk.util.CuratorUtils;
import com.aaron.remoting.dto.RpcRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.curator.framework.CuratorFramework;

import java.net.InetSocketAddress;
import java.util.List;

// 基于zookeeper实现服务发现服务
@Slf4j
public class ZkServiceDiscoveryImpl implements ServiceDiscovery {
    private final LoadBalance loadBalance;

    // 获取LoadBalance接口的具体实现类，使用负载均衡
    public ZkServiceDiscoveryImpl() {
        this.loadBalance = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension("loadBalance");
    }

    // 发现服务，通过服务名，返回套接字服务地址。这里要用到负载均衡
    @Override
    public InetSocketAddress lookupService(RpcRequest rpcRequest) {
        // 通过服务名来进行服务发现，得到服务名对应的所有服务地址集合，去做负载均衡
        String rpcServiceName = rpcRequest.getRpcServiceName();
        CuratorFramework zkClient = CuratorUtils.getZkClient();
        List<String> serviceUrlList = CuratorUtils.getChildrenNodes(zkClient, rpcServiceName);

        if (serviceUrlList == null || serviceUrlList.size() == 0) {
            throw new RpcException(RpcErrorMessageEnum.SERVICE_CAN_NOT_BE_FOUND, rpcServiceName);
        }

        // 我们根据完整的服务名称查找出的服务地址不止一个，那么就使用负载均衡选择其中的一个.
        // 例：targetServiceUrl=192.168.0.1:9999
        String targetServiceUrl = loadBalance.selectServiceAddress(serviceUrlList, rpcRequest);
        log.info("Successfully found the service address:[{}]", targetServiceUrl);
        // 按照冒号进行切分，ip地址与端口号
        String[] socketAddressArray = targetServiceUrl.split(":");
        String host = socketAddressArray[0];
        int port = Integer.parseInt(socketAddressArray[1]);
        // 根据主机名和端口号创建 套接字地址
        return new InetSocketAddress(host, port);
    }
}
